package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class NIOServer implements Runnable {
	private int port = 8888;
	private Charset cs = Charset.forName("gbk");
	private ByteBuffer sBuffer = ByteBuffer.allocate(1024);
	private ByteBuffer rBuffer = ByteBuffer.allocate(1024);
	private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();
	private Selector selector;

	public NIOServer(int port) {
		this.port = port;
		try {
			init();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void init() throws IOException {
		// 打开ServerSocketChannel，用于监听客户端的连接，它是所有客户端连接的父管道
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		// 设置连接为非阻塞模式
		serverSocketChannel.configureBlocking(false);
		// 绑定监听端口
		ServerSocket serverSocket = serverSocketChannel.socket();
		serverSocket.bind(new InetSocketAddress(port));
		// 创建Reactor线程，创建多路复用器并启动线程
		selector = Selector.open();
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("server start on port:" + port);
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			try {
				selector.select();
				Set<SelectionKey> selectionKeys = selector.selectedKeys();
				for (SelectionKey key : selectionKeys) {
					handle(key);
				}
				selectionKeys.clear();
			} catch (Exception e) {
				e.printStackTrace();
				break;
			}

		}
	}

	private void handle(SelectionKey selectionKey) throws IOException, InterruptedException {
		ServerSocketChannel server = null;
		SocketChannel client = null;
		String receiveText = null;
		int count = 0;
		if (selectionKey.isAcceptable()) {
			server = (ServerSocketChannel) selectionKey.channel();
			client = server.accept();
			// 判断client 是否为空
			if (client != null) {
				client.configureBlocking(false);
				client.register(selector, SelectionKey.OP_READ);
			}
			Thread.sleep(10 * 1000);
		} else if (selectionKey.isReadable()) {
			client = (SocketChannel) selectionKey.channel();
			rBuffer.clear();
			count = client.read(rBuffer);
			if (count > 0) {
				rBuffer.flip();
				receiveText = String.valueOf(cs.decode(rBuffer).array());
				System.out.println(client.toString() + ":" + receiveText);
				dispatch(client, receiveText);
				client = (SocketChannel) selectionKey.channel();
				client.register(selector, SelectionKey.OP_READ);
			}
		}
	}

	private void dispatch(SocketChannel client, String info) throws IOException {
		Socket s = client.socket();
		String name = "[" + s.getInetAddress().toString().substring(1) + ":" + Integer.toHexString(client.hashCode()) + "]";
		if (!clientsMap.isEmpty()) {
			for (Map.Entry<String, SocketChannel> entry : clientsMap.entrySet()) {
				SocketChannel temp = entry.getValue();
				if (!client.equals(temp)) {
					sBuffer.clear();
					sBuffer.put((name + ":" + info).getBytes());
					sBuffer.flip();
					temp.write(sBuffer);
				}
			}
		}
		clientsMap.put(name, client);
	}

	public static void main(String[] args) throws InterruptedException {
		// 创建MyServer
		NIOServer server1 = new NIOServer(7778);
		NIOServer server2 = new NIOServer(7777);
		new Thread(server1).start();
		new Thread(server2).start();

	}
}